"""
闭包（Closure）是 Python 中一个重要的概念。

什么是闭包？
闭包是指在一个函数内部定义的函数，并且内部函数引用了外部函数的局部变量。
当外部函数返回这个内部函数时，这些被引用的变量会被保存在内部函数中，形成闭包。

闭包的特点：
1. 必须有一个内嵌函数
2. 内嵌函数必须引用外部函数中的变量
3. 外部函数的返回值必须是内嵌函数

闭包的作用：
1. 可以读取函数内部的变量
2. 让这些变量始终保持在内存中
3. 实现封装和数据隐藏
"""

# 示例1：基本的闭包概念
def outer_func(x):
    """
    外部函数
    :param x: 外部函数的参数
    :return: 内部函数
    """
    def inner_func(y):
        """
        内部函数，引用了外部函数的变量x
        :param y: 内部函数的参数
        :return: x和y的和
        """
        return x + y  # 引用了外部函数的变量x
    return inner_func  # 返回内部函数

# 创建闭包
closure = outer_func(10)
print("闭包示例1:")
print(f"closure(5) = {closure(5)}")  # 输出 15

# 示例2：利用闭包实现计数器
def counter():
    """
    创建一个计数器函数
    :return: 计数函数
    """
    count = 0  # 计数变量
    
    def increment():
        """
        增加计数的内部函数
        """
        nonlocal count  # 使用nonlocal声明访问外部函数的变量
        count += 1
        return count
    
    return increment

# 创建两个独立的计数器
counter1 = counter()
counter2 = counter()

print("\n闭包示例2 - 计数器:")
print(f"counter1(): {counter1()}")  # 输出 1
print(f"counter1(): {counter1()}")  # 输出 2
print(f"counter2(): {counter2()}")  # 输出 1 (独立的计数器)

# 示例3：利用闭包实现配置功能
def create_multiplier(n):
    """
    创建一个乘法器函数
    :param n: 乘数
    :return: 乘法函数
    """
    def multiplier(x):
        """
        乘法函数
        :param x: 被乘数
        :return: 乘积
        """
        return x * n
    
    return multiplier

# 创建不同的乘法器
double = create_multiplier(2)   # 创建双倍函数
triple = create_multiplier(3)   # 创建三倍函数

print("\n闭包示例3 - 乘法器:")
print(f"double(5) = {double(5)}")     # 输出 10
print(f"triple(5) = {triple(5)}")     # 输出 15

# 示例4：查看闭包信息
print("\n闭包信息查看:")
print(f"double.__closure__: {double.__closure__}")
print(f"double.__closure__[0].cell_contents: {double.__closure__[0].cell_contents}")

# 示例5：闭包与普通函数的区别
def normal_func(x, y):
    """
    普通函数
    """
    return x * y

def closure_func_factory(x):
    """
    闭包工厂函数
    """
    def closure_func(y):
        return x * y
    return closure_func

# 比较两种方式
normal_result = normal_func(3, 4)  # 需要同时传入两个参数

# 通过工厂函数创建专门的函数
multiply_by_3 = closure_func_factory(3)
closure_result = multiply_by_3(4)  # 只需要传入一个参数

print("\n闭包与普通函数对比:")
print(f"普通函数结果: {normal_result}")           # 输出 12
print(f"闭包函数结果: {closure_result}")          # 输出 12
print(f"multiply_by_3函数已携带参数3，只需传入一个参数即可")

# 注意事项和常见误区
print("\n闭包的注意事项:")
print("1. 在闭包中修改外部变量需要使用 nonlocal 关键字")
print("2. 闭包会延长变量的生命周期，可能导致内存占用")
print("3. 循环中创建闭包时需要注意变量绑定问题")

# 错误示例：循环中创建闭包的问题
print("\n错误示例 - 循环中创建闭包:")
funcs = []
for i in range(3):
    # 这里创建的lambda函数都会引用同一个变量i
    # 而不是各自创建时i的不同值
    funcs.append(lambda: i)  # 这里所有lambda函数都会引用同一个i

print("调用所有函数的结果:")
for j, func in enumerate(funcs):
    # 由于所有函数都引用同一个变量i，而循环结束时i的值为2
    # 所以这里调用所有函数都会得到结果2，而不是期望的0, 1, 2
    print(f"funcs[{j}](): {func()}")  # 都输出 2，而不是期望的 0, 1, 2

# 正确示例：解决循环中闭包的问题
print("\n正确示例 - 解决循环中闭包问题:")
funcs_correct = []
for i in range(3):
    # 使用默认参数 x=i 将当前循环的i值绑定到参数x上
    # 这样每个lambda函数都有自己独立的x值副本
    funcs_correct.append(lambda x=i: x)  # 使用默认参数绑定当前值

print("调用所有函数的结果:")
for j, func in enumerate(funcs_correct):
    # 由于每个函数都有自己的x值副本，所以能正确输出0, 1, 2
    print(f"funcs_correct[{j}](): {func()}")  # 输出 0, 1, 2
